/* list.c
 * implements interfaces declear in list.h
 * NOTE:
 * functions with prefix '__xxx' may never check arguments || set error code
 * and should be used only by other interfaces who interact with user functions
 */

#include <stdlib.h>
#include <string.h>
#include "list.h"

#ifdef DEBUG_LIST
#include <stdio.h>
#endif

#define LIST_NULL_RETURN(check, ret)    \
        if( NULL == (check)){           \
            return (ret);               \
        }

#define LIST_SET_ERR(list, err)         \
        if( LIST_SUCCESS == (err) ) {   \
            (list)->has_error = FALSE;  \
        } else {                        \
            (list)->has_error = TRUE;   \
        }                               \
        (list)->error_code = err;

static const int max_size = INT_MAX - 1;

typedef struct {
    const int error_code;
    const char *error_string;
} list_error_t;

const static list_error_t list_errors[] = {
        { LIST_SUCCESS, "List Success:Operation Success" },
        { LIST_ERR_ARGVALUE, "List Error: INVALID arguments"},
        { LIST_ERR_CALLBACK, "List Error: Callback Function Return an Error"},
        { LIST_ERR_LEN0, "List Error: List has lenth of 0"},
        { LIST_ERR_NOMEM, "List Error: Lack of Memory"},
        { LIST_ERR_SET_CALLBACKS, "List Error: Can't Set Callback functions"},
        { LIST_ERR_UNKNOWN, "List Error: Unknown Error"},
        { LIST_ERR_LEN_MAX, "List Error: Max Size Has Reached"},
        { LIST_ERR_INCONSISTENT, "List Error: List Maybe Inconsistent Now"}
};

const char *list_get_error_string(const int error_code)
{
    int count = sizeof(list_errors)/(sizeof(list_error_t));
    for(count --; count >= 0 ; count --){
        if(error_code == list_errors[count].error_code){
            return (list_errors[count].error_string);
        }
    }

    return NULL;
}

const char *list_get_last_error_string(list_t *list)
{
    if( NULL == list){
        return list_get_error_string(LIST_ERR_ARGVALUE);
    }

    const int error_code = list->error_code;
    int count = sizeof(list_errors)/(sizeof(list_error_t));
    for(count --; count >= 0 ; count --){
        if(error_code == list_errors[count].error_code){
            return (list_errors[count].error_string);
        }
    }
    return list_get_error_string(LIST_ERR_UNKNOWN);
}

list_t *list_new(data_op_t *default_callback)
{
    list_t *list;
    list = (list_t *) malloc (sizeof(list_t));

    if( NULL != list ) {
        list -> __len = 0;
        list -> __first = list->__last = NULL;

        LIST_SET_ERR(list, LIST_SUCCESS);

       if((list -> __default_callback = (data_op_t *) malloc (sizeof (data_op_t))) != NULL ) {
           if(default_callback != NULL){
               memcpy(list->__default_callback, default_callback, sizeof(data_op_t));
           } else {
               memset(list->__default_callback, 0, sizeof(data_op_t));
           }
       } else {
           LIST_SET_ERR(list, LIST_ERR_SET_CALLBACKS);
       }
        
    }
#ifdef DEBUG_LIST
    if( NULL == list ) {
        perror("malloc return error");
    }
#endif

    return list;
}

int     list_reset_callbacks(list_t *list, data_op_t *default_callback)
{
    LIST_NULL_RETURN(list, LIST_ERR_ARGVALUE);

    LIST_SET_ERR(list, LIST_SUCCESS);

    if( NULL != default_callback){
        memcpy(list->__default_callback, default_callback, sizeof(data_op_t));
    } else {
        memset(list->__default_callback, 0, sizeof(data_op_t));
    }

    return 0;
}

inline int list_size(list_t *list) 
{ 
    LIST_NULL_RETURN(list, LIST_ERR_ARGVALUE);

    LIST_SET_ERR(list, LIST_SUCCESS);
    return list->__len; 
}

int list_del_first(list_t *list, const func_free_t func_free)
{
    LIST_NULL_RETURN(list, LIST_ERR_ARGVALUE);

    LIST_SET_ERR(list, LIST_SUCCESS);

    if ( 0 == list->__len) {
        LIST_SET_ERR(list, LIST_ERR_LEN0);
        return 0;
    }

    node_t *toDel = list->__first;

    func_free_t do_free = ( NULL == func_free ) ? (list->__default_callback->free) : func_free;
    if( NULL != do_free ){
        if( 0 != do_free(toDel->data)){
            LIST_SET_ERR(list, LIST_ERR_CALLBACK);
            return LIST_ERR_CALLBACK;
        }
    }

    if ( list->__len == 1) {
        list->__first = list->__last = NULL;
    } else {
        //the second node in the list should have a prev Point to NULL
        toDel->next->prev = NULL;     
        list->__first = list->__first->next;
    }
    free(toDel);
    (list->__len) --;

#ifdef DEBUG_LIST
    printf("Now have %d elements @@ list_del_first()\n", list ->__len);
#endif
    return 0;
}

static int __direct_cmp(const void *larger, const void *smaller)
{
    if(larger > smaller){
        return 1;
    }else if(larger < smaller){
        return -1;
    } else {
        return 0;
    }
}

int     list_del_as(list_t *list, const void *data, func_cmp_t func_cmp, func_free_t func_free)
{
    LIST_NULL_RETURN(list, LIST_ERR_ARGVALUE);
    LIST_SET_ERR(list, LIST_SUCCESS);

    if( list->__len == 0 ){
        return 0;
    }

    int num_dels = 0;
    node_t *current, *prev;
    func_free_t do_free = ( NULL == func_free ) ? (list->__default_callback->free) : func_free;
    func_cmp_t do_cmp = ( NULL == func_cmp ) ? (list->__default_callback->cmp) : func_cmp;
    if(NULL == do_cmp){
        do_cmp = __direct_cmp;
    }
    
    for(current = prev = list->__first; list->__len > 0 && NULL != current; ){
        if( do_cmp(current->data, data) == 0){
            if(current->prev == NULL){
                list_del_first(list, do_free);
                current = prev = list->__first;
            } else if (current->next == NULL){
                list_del_last(list, do_free);
                num_dels ++;
                break;
            } else {
                if(NULL != do_free){
                    if(do_free(current->data) != 0){
                        LIST_SET_ERR(list, LIST_ERR_CALLBACK);
                        return LIST_ERR_CALLBACK;
                    }
                }
                current->prev->next = current->next;
                current->next->prev = current->prev;

                free(current);
                current = prev->next;

                (list->__len) --;
            }
            num_dels ++;
        } else {
            if(current != prev){
                prev = prev->next;
            }
            current=current->next;
        }
    }
    return num_dels;
}

int     list_contains(list_t *list, const void *data, func_cmp_t func_cmp){
    LIST_NULL_RETURN(list, LIST_ERR_ARGVALUE);
    LIST_SET_ERR(list, LIST_SUCCESS);
    if( NULL == data){
        LIST_SET_ERR(list, LIST_ERR_ARGVALUE);
        return LIST_ERR_ARGVALUE;
    }

    if(list->__len == 0){
        return FALSE;
    }
    node_t *current = list->__first;
    func_cmp_t do_cmp = __direct_cmp;

    if(func_cmp != NULL){
        do_cmp = func_cmp;
    }else if(list->__default_callback->cmp != NULL){
        do_cmp = list->__default_callback->cmp;
    }

    int count = 0;
    while(current != NULL){
        if(do_cmp(current->data, data) == 0){
            count ++;
        }
        current = current->next;
    }
    return count;
}

int list_add_first(list_t *list, const void *data, const func_copy_t func_copy)
{
    LIST_NULL_RETURN(list, LIST_ERR_ARGVALUE);
    LIST_SET_ERR(list, LIST_SUCCESS);

    if (list->__len == max_size) {
        LIST_SET_ERR(list, LIST_ERR_LEN_MAX);
        return LIST_ERR_LEN_MAX;
    }

    node_t *pNode = (node_t *) malloc (sizeof(node_t));
    if(NULL == pNode){
        LIST_SET_ERR(list, LIST_ERR_NOMEM);
        return -1;
    }

    func_copy_t do_copy = ( NULL == func_copy ) ? (list->__default_callback->copy) : func_copy;
    if( NULL != do_copy ){
        if ( NULL == do_copy( &(pNode->data), data) ){
            LIST_SET_ERR(list, LIST_ERR_CALLBACK);
            free(pNode);
            return LIST_ERR_CALLBACK;
        }
    } else {
        pNode->data = (void *)data;
    }

    //this node will become to the first node
    if(list->__len > 0){
        list->__first->prev = pNode;
    }
    pNode->prev = NULL; 
    pNode->next = list->__first;
    list->__first = pNode;
    if(0 == list->__len) {
        list->__last = pNode;
    }
    (list->__len) ++;

#ifdef DEBUG_LIST
    printf("now have %d elements @@ list_add_first() ", list->__len);
#endif

    return 0;
}

void *list_get_first(list_t *list)
{
    LIST_NULL_RETURN(list, NULL);
    LIST_SET_ERR(list, LIST_SUCCESS);

    if( 0 != list->__len){
        LIST_SET_ERR(list, LIST_SUCCESS);
        return list->__first->data;
    } else {
        LIST_SET_ERR(list, LIST_ERR_LEN0);
        return NULL;
    }
}

/*return:   NULL if length <= 0;
 *          else a pointer point to the last node;
 */
static node_t *__last_node(const list_t *list)
{
#ifdef DEBUG_LIST
    node_t *current = NULL;
    int count = 1;
#endif
    if (list->__len <= 0) {
#ifdef DEBUG_LIST
        if (list->__last != NULL || list->__first != NULL) {
            printf("WARNING: list maybe dirty: __last||__first != NULL while list length <= 0");
        }
#endif
        return NULL;
    } else {
#ifdef DEBUG_LIST
        current = list->__first;
        while (NULL != current->next) {
            current = current->next;
            count ++;
            if (NULL == current->next){
                if ( count != list->__len){
                    printf("WARNING: list may be dirty: length!= nodes number\n");
                }
                if (list->__last != current){
                    printf("WARNING: list may be dirty: __last is not the last node\n");
                }
            }
        }
        return current;
#else
        return list->__last;
#endif
    }
}

void *list_get_last(list_t *list)
{
    LIST_NULL_RETURN(list, NULL);
    LIST_SET_ERR(list, LIST_SUCCESS);

    if( 0 == list->__len){
        LIST_SET_ERR(list, LIST_ERR_LEN0);
        return NULL;
    }

    void *data = NULL;

    node_t *last = __last_node(list);
    if(last){
        data = last->data;
    } else {
        LIST_SET_ERR(list, LIST_ERR_UNKNOWN);
    }
    return data;
}

int list_add_last(list_t *list, const void *data, const func_copy_t func_copy)
{

    LIST_NULL_RETURN(list, LIST_ERR_ARGVALUE);
    LIST_SET_ERR(list, LIST_SUCCESS);

    if (list->__len == max_size) {
        LIST_SET_ERR(list, LIST_ERR_LEN_MAX);
        return LIST_ERR_LEN_MAX;
    }

    if (0 == list->__len){
        return list_add_first(list, data, func_copy);
    }

    func_copy_t do_copy = ( NULL == func_copy ) ? (list->__default_callback->copy) : func_copy;
    node_t *last = __last_node(list);

    node_t *new_node = (node_t *)malloc(sizeof(node_t));
    if(!new_node){
#ifdef DEBUG_LIST
        perror("malloc failure:");
#endif
        LIST_SET_ERR(list, LIST_ERR_NOMEM);
        return LIST_ERR_NOMEM;
    } else {
        if( NULL == do_copy) {
            new_node->data = (void *)data;
        } else {
            if( NULL == do_copy( &(new_node->data), data)) {
                LIST_SET_ERR(list, LIST_ERR_CALLBACK);
                free(new_node);
                return LIST_ERR_CALLBACK;
            }
        }
        new_node->prev = last;
        new_node->next = NULL;
        list->__last = new_node;
    }

    if (last) {
        last->next = new_node;
    }

    (list->__len) ++;

#ifdef DEBUG_LIST
    printf("now have %d elements @@ list_add_last()\n", list->__len);
#endif

    return 0;
}

int list_del_last(list_t *list, const func_free_t func_free)
{

    LIST_NULL_RETURN(list, LIST_ERR_ARGVALUE);
    LIST_SET_ERR(list, LIST_SUCCESS);

    node_t *last = __last_node(list);
    if( !last ){
#ifdef DEBUG_LIST
        puts("have no element to delete @ list_del_last()\n");
#endif
        LIST_SET_ERR(list, LIST_SUCCESS);
        return 0;
    }

    if( 0 == list->__len){
        LIST_SET_ERR(list, LIST_SUCCESS);
        return 0;
    } else if (1 == list->__len) {
        return list_del_first(list, func_free);
    }

    func_free_t do_free = ( NULL == func_free ) ? (list->__default_callback->free) : func_free;
    if( NULL != do_free ){
        if( 0 != do_free( last->data) ){

            LIST_SET_ERR(list, LIST_ERR_CALLBACK);
            return LIST_ERR_CALLBACK;
        }
    }
    
    list->__last = last->prev;
    last->prev->next = NULL;
    free(last);

    (list->__len) --;

#ifdef DEBUG_LIST
    printf("now have %d elements @@ list_del_last()", list->__len);
#endif

    return 0;
}

int list_for_each(list_t *list, const func_foreach_t func_foreach)
{
    LIST_NULL_RETURN(list, LIST_ERR_ARGVALUE);
    func_foreach_t do_each = ( NULL == func_foreach ) ? (list->__default_callback->foreach) : func_foreach;

    LIST_SET_ERR(list, LIST_SUCCESS);
    if( NULL == do_each){
        return 0;
    }

    int result = 0;
    node_t *pNode = list->__first;

#ifdef DEBUG_LIST
    int count_nodes = 0;
    if( NULL != pNode){
        if(pNode -> prev != NULL){
            printf("WARNING: list may be dirty:__first-> prev!= NULL\n");
        }
    }
#endif

    for(; NULL != pNode; pNode = pNode->next){

        result = do_each(pNode->data);
		if( 0 != result ){
            if ( result > 0) {
                LIST_SET_ERR(list, LIST_SUCCESS);
            } else {
                LIST_SET_ERR(list, LIST_ERR_CALLBACK);
            } 
			return result;
		}
#ifdef DEBUG_LIST
        count_nodes ++;
        if(pNode->next == NULL) {
            if(count_nodes != list->__len){
                printf("WARNING: list may be dirty: length!= nodes number\n");
            }
        }
#endif
    }
    return 0;
}

int list_clear(list_t *list, const func_free_t func_free)
{
    LIST_NULL_RETURN(list, LIST_ERR_ARGVALUE);
    LIST_SET_ERR(list, LIST_SUCCESS);
    int result = 0;

    for(; (list)->__len > 0; ){
        result = list_del_first(list, func_free);
        if( 0 != result ){
            return result;
        }
    }

    return 0;
}

void *list_destroy(list_t **list, const func_free_t func_free)
{
    LIST_NULL_RETURN(*list, NULL);

    LIST_SET_ERR(*list, LIST_SUCCESS);
    
    list_clear(*list, func_free);

    free((*list)->__default_callback);
    free(*list);
    *list = NULL;
    return NULL;
}

long  list_cmp(const list_t *larger, const list_t *smaller, const func_cmp_t func_cmp)
{
    node_t *curr_l, *curr_s;
    int cmp_res = 0;
    func_cmp_t do_cmp = (NULL == func_cmp) ? __direct_cmp : func_cmp;

    if (NULL != larger && NULL != smaller){

        for (curr_l = larger->__first, curr_s = smaller->__first;
                curr_l != NULL && curr_s != NULL;
                curr_l = curr_l->next, curr_s = curr_s->next){

            cmp_res = do_cmp(curr_l->data, curr_s->data);
            if (cmp_res != 0) {
                return cmp_res;
            }
        }
        return ((unsigned long)curr_l - (unsigned long)curr_s);
    }

    return ((unsigned long)larger - (unsigned long)smaller);
}

list_t *list_new_with_copy(const list_t *list_from, const func_copy_t func_copy)
{
    LIST_NULL_RETURN(list_from, NULL);

    list_t *list = list_new(list_from->__default_callback);

    node_t *current = __last_node(list_from);
    if (NULL == current) {
        return list;
    }

    while (current != NULL) {
        list_add_first(list, current->data, func_copy);
        current = current->prev;
    }

#ifdef DEBUG_LIST
    printf("list cmp: list & list_from:%d\n", list_cmp(list, list_from, (func_cmp_t)strcmp));
#endif
    
    return list;
}

list_t *list_join(list_t *front, const list_t *rear, func_copy_t func_copy, func_free_t func_free)
{
    LIST_NULL_RETURN( (void *) (((long) front) | ((long) rear)), NULL);
    LIST_SET_ERR(front, LIST_SUCCESS);
    
    if (max_size - front->__len < rear->__len) {
        LIST_SET_ERR(front, LIST_ERR_LEN_MAX);
        return front;
    }

    list_t *temp = list_new_with_copy(rear, func_copy);

#ifdef DEBUG_LIST
    if (temp->__len != rear->__len){
        printf("WARNING: list copy result is not correct\n");
    }
#endif

    node_t *last = __last_node(front);

    if((NULL == temp) ){
        LIST_SET_ERR(front, LIST_ERR_NOMEM);
        return front;
    }

    if (front->__len == 0) {
        front->__first = temp->__first;
    } else {
        last->next = temp->__first;
    }

    if(temp->__len > 0){
        temp->__first->prev = last;
        front->__last = temp->__last;
    } //else front->__last is as formal 
    front->__len = front->__len + rear->__len;
    
    free(temp->__default_callback);
    free(temp);

#ifdef DEBUG_LIST
    printf("list joined, now has %d elements in total\n", front->__len);
#endif
    
    return front;
}

/* split list into two lists
 * note: this function won't take deep copy, and change to the original list
 *       will take effects on the splited ones, so the *orig_list will be NULL after return.
 * @orig_list:      list to be splited
 * @lists:          list_t* array contains result(need not allocate momery hold list head)
 * @pivot:          pivot node, NULL will make lists[0] empty
 * @append_last:    append pivot to the last of first list if TRUE;
 *                  insert to the head of the second list if FALSE;
 * @return:     array contains the list(s), NULL on error
 */
static list_t **__split_list(list_t **orig_list, list_t *lists[],  node_t *pivot, const BOOLEAN append_last)
{
    list_t *list = *orig_list;

    if (NULL == list){
#ifdef DEBUG_LIST 
        puts("list is NULL @@ __split\n");
#endif 
        return NULL;
    }
    
    int i = 0;
    while (i < 2) {
        if ((lists[i] = list_new(list->__default_callback)) == NULL ){
            if (1 == i) {
                list_destroy(&(lists[0]), list->__default_callback->free);
                lists[0] = lists[1] = NULL;
            }
            return NULL;
        }
        i ++;
    }//now have two memory block hold two list_t structure

    node_t *append = (append_last == TRUE || NULL == pivot) ? pivot : pivot->prev; 
    //now have append at the lists[0]'s last according to @append_last
    
    node_t *walk = list->__first;
    i = 0;
    if (append != NULL) {
        while (walk != NULL){
            i ++;
            if (walk == append){
                break;
            }
            walk = walk->next;
        }
    }//now i indicate how many nodes will contained in the lists[0]

    if ( 0 != i ){
        lists[0]->__first = list->__first;
        lists[1]->__first = append->next;

        if (append->next != NULL) {
            append->next->prev = NULL;
        }

        append->next = NULL;
    } else { // i == 0: list is empty || append == NULL(lists[0] will be empty)
        lists[1]->__first = list->__first;
        lists[0]->__first = NULL;
    }
    lists[0]->__last = append;
    lists[1]->__last = list->__last;
    lists[0]->__len = i;
    lists[1]->__len = list->__len - i;

    free(list->__default_callback);
    free(list);
    *orig_list = NULL;

    return lists;
}

list_t **list_split(list_t **orig_list, list_t *lists[], const int num_in_first)
{
    //check arguments
    LIST_NULL_RETURN( (*orig_list), NULL);
    list_t *list = *(orig_list);
    LIST_SET_ERR(list, LIST_SUCCESS);

    if (lists == NULL || num_in_first < 0) {
        LIST_SET_ERR( list, LIST_ERR_ARGVALUE);
        return NULL;
    }

    int i = 0;
    node_t *walk = list->__first;
    while (walk != NULL){
        i ++;
        if ( num_in_first == i){
            break;
        }
        walk = walk->next;
    }//find which node as pivot node

    return __split_list( orig_list, lists, walk, TRUE);
}


#define __replace_node(list, x1, x2)        \
            if ((x1)->prev != NULL) {       \
                (x1)->prev->next = (x2);    \
            } else {                        \
                (list)->__first = (x2);     \
            }                               \
            if ((x1)->next != NULL) {       \
                (x1)->next->prev = (x2);    \
            }

#define __set_if_last_node(list, x)         \
            if ((x)->next == NULL) {        \
                (list)->__last = (x);       \
            }

/* swap position of two node
 * @list:   list operate on
 * @n1:     first node
 * @n2:     second node
 * @return: 0 if no error , or NEGETIVE indicate an error
 */
int  __swap_nodes_order(list_t *list, node_t *n1, node_t *n2)
{

    if (n1 == n2){
        return 0;
    }

    node_t *swap = NULL;
    node_t **pprev_n = NULL;       //point to n1->perv->next or list->__first

    if (n1->next == n2 || n2->next == n1){//n1 besides n2
        if(n2->next == n1) {
            swap = n1;
            n1 = n2;
            n2 = swap;
        }//now n1->next = n2
        pprev_n = (n1->prev == NULL) ? &(list->__first) : &(n1->prev->next);
        
        swap = n2->next;
        if(swap != NULL) {
            swap->prev = n1;
        }
        n2->next = n1;
        n2->prev = n1->prev;

        *(pprev_n) = n2;
        n1->prev = n2;
        n1->next = swap;
            //now n1 at the end

        if (n1->next == NULL) {
            list->__last = n1;
        }
        
    } else {//normal
        __replace_node(list, n1, n2);
        __replace_node(list, n2, n1);

        swap = n1->next;
        n1->next = n2->next;
        n2->next = swap;

        swap = n1->prev;
        n1->prev = n2->prev;
        n2->prev = swap;

        __set_if_last_node(list, n1);
        __set_if_last_node(list, n2);
    }

    return 0;
}
#undef __replace_node
#undef __set_if_last_node

#define __swap_nodes_data(n1, n2, swap)     \
    (swap) = (n1)->data;                    \
    (n1)->data = (n2)->data;                \
    (n2)->data = (swap);

/* swap nodes at index1 and index2 (will not move data , only change pointers)
 * @list:   list operate on
 * @index1  first node's index
 * @index2: second nodes's index
 * @return : 0 on success, else a negative number
 */
int list_swap(list_t *list, const int index1, const int index2)
{
    //check parament
    LIST_NULL_RETURN(list, LIST_ERR_ARGVALUE);
    if (index1 <= 0 || index2 <= 0 || (index1 > index2 ? index1 : index2) > list->__len){
        LIST_SET_ERR(list, LIST_ERR_ARGVALUE);
        return LIST_ERR_ARGVALUE;
    }

    if (index1 == index2) { //need to do nothing
        return 0;
    }

    node_t *n1, *n2;
    node_t *walk = NULL;
    const int min = (index1 < index2) ? index1 : index2;
    const int max = (index1 > index2) ? index1 : index2;
    
    int count;
    for(count = 0, walk = list->__first, n1 = n2 = NULL; walk != NULL; walk = walk->next){
        count ++;
        if (min == count){
            n1 = walk;
        } else if ( max == count){
            n2 = walk;
            break;
        }
    }

    void *swap = NULL;
    __swap_nodes_data(n1, n2, swap);

    return 0;
}

static node_t *__qsort_list_partion(node_t *low, node_t *high, func_cmp_t func_cmp)
{
    void *swap = NULL;
    void *pivot = NULL;

    pivot = low->data;
    while (low != high) {
        while(low != high && func_cmp(high->data, pivot) >= 0) {
            high = high->prev;
        }
        __swap_nodes_data(low, high, swap);
        
        while(low != high && func_cmp(pivot, low->data) >= 0) {
            low = low->next;
        }
        __swap_nodes_data(low, high, swap);
    }
    
    return low;
}

static int __qsort_list(node_t *low, node_t *high, func_cmp_t func_cmp)
{
    node_t *result = __qsort_list_partion(low, high, func_cmp);

    if (result != low) {
        __qsort_list(low, result->prev, func_cmp);
    }

    if (result != high) {
        __qsort_list(result->next, high, func_cmp);
    }
    
    return 0;
}

int list_qsort(list_t *list, func_cmp_t func_cmp)
{
    LIST_NULL_RETURN(list, LIST_ERR_ARGVALUE);
    LIST_SET_ERR(list, LIST_SUCCESS);

    if (list->__len == 0 || list->__len == 1) {
        return 0;
    }

    func_cmp = (NULL == func_cmp) ? list->__default_callback->cmp : func_cmp;
    if(NULL == func_cmp) {
        func_cmp = __direct_cmp;
    }

    return __qsort_list(list->__first, list->__last, func_cmp);
}

int list_reverse(list_t *list)
{
    LIST_NULL_RETURN(list, LIST_ERR_ARGVALUE);
    LIST_SET_ERR(list, LIST_SUCCESS);

    if(list->__len == 0 || list->__len == 1) {
        return 0;
    }

    void *swap = NULL;
    node_t *low = list->__first;
    node_t *high = __last_node(list);

    while(low != high && high->next != low){
        __swap_nodes_data(low, high, swap);
        
        low = low->next;
        high = high->prev;
    }
    
    return 0;
}

